﻿/*!
* @file ConfFileReader.cpp
* @brief 設定ファイル（各行が param:value の形式、#で始まる行はコメント）を読み込む<br>
* 読み込んだ後は、ハッシュのようにアクセスできる
* @author Yasutomo Kawanishi
* @date Last Change:2010/Jan/08 12:05:29.
* */

#include "ConfFileReader.h"
#include <iostream>
#include <fstream>
#include <cstdlib>

namespace mmpl{

	ConfFileReader::ConfFileReader(const std::map<std::string,std::string>& conf){
		params.insert(std::make_pair("default",conf));
	}

	ConfFileReader::ConfFileReader(const std::string& filename){
		std::ifstream ifs(filename.c_str());
		if(!ifs){
			std::cerr << "No such file: " << filename << std::endl;
			abort();
		}

		std::string temp,key,value;
		std::string::size_type index;
		std::string current_group="default";
		char buf[BUFSIZ];
		while(!ifs.eof()){
			ifs.getline(buf,BUFSIZ);
			temp=buf;
			//! 空行のとき
			if(temp.empty())continue;
			//! コメントの時
			if(temp[0]=='#')continue;
			//! グループ名の時
			if(temp[0]=='['){
				if((index=temp.find("]"))==std::string::npos)continue;
				current_group=temp.substr(1,index-1);
				//std::cout << current_group << std::endl;
				continue;
			}
			//! パラメータの時
			if((index=temp.find(":"))==std::string::npos)continue;
			key=temp.substr(0,index);
			value=temp.substr(index+1,temp.size()-index-1);
			std::map<std::string,std::map<std::string,std::string> >::iterator it=params.find(current_group);
			if(it!=params.end()) it->second.insert(std::make_pair(key,value));
			else{
				std::map<std::string,std::string> temp;
				temp.insert(std::make_pair(key,value));
				params.insert(std::make_pair(current_group,temp));
			}
		}
	}

	ConfFileReader::~ConfFileReader(){}

	/** 
	* @brief 指定したパラメータ名の値を返す
	* 
	* @param key パラメータ名
	* 
	* @return 最初に見つかった値
	*/
	std::string& ConfFileReader::operator[](const std::string& key){
		for(std::map<std::string,std::map<std::string, std::string> >::iterator it=params.begin();it!=params.end();it++)
			if(it->second.find(key)!=it->second.end())return it->second[key];
		if(params["default"][key]=="")
			std::cerr << "警告: パラメータ " << key << "がありません。" << std::endl;
		return params["default"][key];
	}

	/** 
	* @brief 各グループを一つにまとめて、パラメータと値の map を返す
	* 
	* @return パラメータと値の map
	*/
	std::map<std::string,std::string> ConfFileReader::getParams()const{
		std::map<std::string,std::string> data;
		for(std::map<std::string,std::map<std::string, std::string> >::const_iterator it=params.begin();it!=params.end();it++){
			//! default グループならそのままマージ
			if(it->first=="default") data.insert(it->second.begin(),it->second.end());
			//! それ以外なら グループ名.パラメータ名 に変換
			else{
				for(std::map<std::string,std::string>::const_iterator it2=it->second.begin();it2!=it->second.end();it2++)
					data.insert(std::make_pair(it->first+"."+it2->first,it2->second));
			}
		}
		return data;
	}

	/** 
	* @brief 指定したグループに属するパラメータと値の map を返す
	* 
	* @param groupname グループ名
	* 
	* @return パラメータと値の map
	*/
	std::map<std::string,std::string> ConfFileReader::getParams(const std::string& groupname)const{
		return params.find(groupname)->second;
	}

	/** 
	* @brief 最初に見つかった指定したパラメータのイテレータを返す
	* 
	* @param key 指定したパラメータ名
	* 
	* @return イテレータ
	*/
	std::map<std::string, std::string>::iterator ConfFileReader::find(const std::string& key){
		for(std::map<std::string,std::map<std::string, std::string> >::iterator it=params.begin();it!=params.end();it++)
			if(it->second.find(key)!=it->second.end())return it->second.find(key);
		return params["default"].end();
	}

	std::set<std::string> ConfFileReader::getGroupNames()const{
		std::set<std::string> data;
		for(std::map<std::string,std::map<std::string, std::string> >::const_iterator it=params.begin();it!=params.end();it++)
			data.insert(it->first);
		return data;
	}

	/*
	@brief keyがConfFileで書かれていたかどうかを調べる
	@param key 存在の有無を知りたいパラメタの名前
	@return 存在すればtrue, なければfalseを返す
	*/
	bool ConfFileReader::hasParam(const std::string& key,const std::string& group)const{
		if(params.find(group)==params.end()) return false;
		return params.find(group)->second.find(key)!=params.find(group)->second.end();
	}
}